/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_LFFREESTACK_H
#define M_LFFREESTACK_H

#include "lfstack.h"
#include "exception.h"

namespace Engine
{
	namespace LockFree
	{
		/**
		*   Class implements memory allocator with lock-free synchronization.
		*/
		template<typename T>
		class FreeList
		{
		public:
			/**
			*   Constructor.
			*   @param cObjects count of objects to create(hold).
			*/
			FreeList(uint32_t cObjects) : m_cObjects(cObjects)
			{
#if defined(_DEBUG) && defined(_MSC_VER)
				m_pObjects = new(_CLIENT_BLOCK,__FILE__, __LINE__) node<T>[cObjects];
#else
				m_pObjects = new node<T>[cObjects];
#endif
				FreeAll();
			}

			/**
			*   Destructor.
			*/
			~FreeList()
			{
#ifdef _DEBUG
				for(uint32_t ix = 0; ix < m_cObjects; ++ix)
				{
					Assert(m_Freelist.Pop() != 0);
				}
#endif
				delete[] m_pObjects;
			}

			/**
			*   Return size of list.
			*/
			unsigned int GetSize()const {return m_cObjects;}

			/**
			*   Clear acquired nodes list.
			*/
			void FreeAll()
			{
				for(uint32_t ix = 0; ix < m_cObjects; ++ix)
				{
					m_Freelist.Push(&m_pObjects[ix]);
				}
			}

			/**
			*   Acquired new node (create object).
			*/
			T * NewInstance()
			{
				node<T> * pInstance = m_Freelist.Pop();
#ifdef _DEBUG
				Assert(reinterpret_cast<node<T> *>(pInstance)>=&m_pObjects[0]&&reinterpret_cast<node<T> *>(pInstance)<=&m_pObjects[m_cObjects]);
#endif
				return new(&pInstance->value) T;
			}

			/**
			*   Free acquired node (delete object).
			*/
			void FreeInstance(T * pInstance)
			{
#ifdef _DEBUG
				Assert(reinterpret_cast<node<T> *>(pInstance)>=&m_pObjects[0]&&reinterpret_cast<node<T> *>(pInstance)<=&m_pObjects[m_cObjects]);
#endif
				pInstance->~T();
				m_Freelist.Push(reinterpret_cast<node<T> *>(pInstance));
			}

		private:

			FreeList(const FreeList&);
			FreeList& operator=(const FreeList&);

		private:

			Stack<T>       m_Freelist; ///< object holds acquired memory nodes.
			node<T>*       m_pObjects; ///< number of available memory nodes.
			const uint32_t m_cObjects; ///< array of memory nodes.
		};
	}
}

#endif
